
#include "Core/PlayerZDCharacter.h"

#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Components/BoxComponent.h"
#include "Core/EnemyZDCharacter.h"
#include "Core/PJGameInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/GameplayStatics.h"
#include "UI/PlayerHUD.h"

APlayerZDCharacter::APlayerZDCharacter()
{
	PrimaryActorTick.bCanEverTick = true;

	SpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	AttackCollisionBox = CreateDefaultSubobject<UBoxComponent>(TEXT("AttackCollision"));
	
	SpringArmComponent->SetupAttachment(RootComponent);
	CameraComponent->SetupAttachment(SpringArmComponent, USpringArmComponent::SocketName);
	AttackCollisionBox->SetupAttachment(RootComponent);
	
	SpringArmComponent->bDoCollisionTest = false;
}

void APlayerZDCharacter::BeginPlay()
{
	Super::BeginPlay();

	 
	if (const APlayerController* PlayerController = Cast<APlayerController>(Controller))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(InputMappingContext, 0);
		}
	}	

	MyGameInstance = Cast<UPJGameInstance>(GetGameInstance());
	if (MyGameInstance)
	{
		HitPoints = MyGameInstance->PlayerHP;
		if (MyGameInstance->IsDoubleJumpUnlock)
		{
			UnlockDoubleJump();
		}
	}
	

	OnAttackOverrideEndDelegate.BindUObject(this, &APlayerZDCharacter::OnAttackOverrideAnimEnd);
	AttackCollisionBox->OnComponentBeginOverlap.AddDynamic(this, &APlayerZDCharacter::AttackBoxOverlapBegin);
	EnableAttackCollisionBox(false);

	if (PlayerHUDClass)
	{
		PlayerHUDWidget = CreateWidget<UPlayerHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0), PlayerHUDClass);
		if (PlayerHUDWidget)
		{
			PlayerHUDWidget->AddToPlayerScreen();
			PlayerHUDWidget->SetHP(HitPoints);
			PlayerHUDWidget->SetDiamonds(MyGameInstance->DiamondCount);
			PlayerHUDWidget->SetLevel(MyGameInstance->CurrentLevelIndex);
		}
	}
}

void APlayerZDCharacter::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
}

void APlayerZDCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &APlayerZDCharacter::Move);

		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &APlayerZDCharacter::JumpStarted);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &APlayerZDCharacter::JumpEnded);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Canceled, this, &APlayerZDCharacter::JumpEnded);

		EnhancedInputComponent->BindAction(AttackAction, ETriggerEvent::Started, this, &APlayerZDCharacter::Attack);
		EnhancedInputComponent->BindAction(ExitGameAction, ETriggerEvent::Completed, this, &APlayerZDCharacter::QuitGame);
	}
	
}

void APlayerZDCharacter::Move(const FInputActionValue& Value)
{
	if (IsAlive && CanMove && !IsStunned)
	{
		const float MoveInputValue = Value.Get<float>();
		AddMovementInput(FVector::ForwardVector, MoveInputValue);
		UpdateDirection(MoveInputValue);
	}
}

void APlayerZDCharacter::JumpStarted(const FInputActionValue& Value)
{
	if (IsAlive && CanMove && !IsStunned)
	{
		Jump();
	}
}

void APlayerZDCharacter::JumpEnded(const FInputActionValue& Value)
{
	StopJumping();
}

void APlayerZDCharacter::Attack(const FInputActionValue& Value)
{
	if (IsAlive && CanAttack && !IsStunned)
	{
		CanAttack = false;
		CanMove = false;

		// EnableAttackCollisionBox(true);
		
		// 参数说明：1.动画Sequence；2.插槽名称；3.播放速度；4.播放起始位置；5.播放结束回调（代理）
		GetAnimInstance()->PlayAnimationOverride(AttackAnimSequence, FName("DefaultSlot"),  1.0f, 0.0f, OnAttackOverrideEndDelegate);
	}
}

void APlayerZDCharacter::OnAttackOverrideAnimEnd(bool Completed)
{
	if (IsActive && IsAlive)
	{
		CanAttack = true;
		CanMove = true;
	}

	// EnableAttackCollisionBox(false);
}

void APlayerZDCharacter::UpdateDirection(float MoveDirection)
{
	FRotator CurrentRotator = GetControlRotation();
	if (MoveDirection < 0.0f)
	{
		if (CurrentRotator.Yaw != 180.01f)
		{
			Controller->SetControlRotation(FRotator(CurrentRotator.Pitch, 180.0f, CurrentRotator.Roll));
		}
	}
	else if (MoveDirection > 0.0f)
	{
		if (CurrentRotator.Yaw != 0.0f)
		{
			Controller->SetControlRotation(FRotator(CurrentRotator.Pitch, 0.0f, CurrentRotator.Roll));
		}	
	}
}

void APlayerZDCharacter::AttackBoxOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	AEnemyZDCharacter* Enemy = Cast<AEnemyZDCharacter>(OtherActor);
	if (Enemy)
	{
		Enemy->TakeDamage(AttackDamage, AttackStunDuration);
		GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, Enemy->GetName());
	}
}

void APlayerZDCharacter::EnableAttackCollisionBox(bool Enabled)
{
	if (Enabled)
	{
		AttackCollisionBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
		AttackCollisionBox->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
	}
	else
	{
		AttackCollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		AttackCollisionBox->SetCollisionResponseToChannel(ECC_Pawn, ECR_Ignore);
	}
	
}

void APlayerZDCharacter::TakeDamage(int DamageAmount, float StunDuration)
{
	if (!IsAlive) return;
	if (!IsActive) return;

	Stun(StunDuration);
	UpdateHP(HitPoints - DamageAmount);

	if (HitPoints <= 0)
	{
		// 死亡
		UpdateHP(0);

		IsAlive = false;
		CanMove = false;
		CanAttack = false;

		GetAnimInstance()->JumpToNode(FName("Jump_Die"), FName("PlayerStateMachine"));
		EnableAttackCollisionBox(false);

		constexpr float RestartDelay = 3.0f;
		GetWorldTimerManager().SetTimer(RestartTimer, this, &APlayerZDCharacter::OnRestartTimerTimeout, 1.0f, false, RestartDelay);
	}
	else
	{
		IsStunned = true;
		
		// 受伤
		GetAnimInstance()->JumpToNode(FName("Jump_TakeHit"), FName("PlayerStateMachine"));
	}
	
	
	
}

void APlayerZDCharacter::UpdateHP(int NewHP)
{
	HitPoints = NewHP;
	MyGameInstance->PlayerHP = HitPoints;
	PlayerHUDWidget->SetHP(HitPoints);
}

void APlayerZDCharacter::Stun(float DurationInSeconds)
{
	IsStunned = true;
	if (GetWorldTimerManager().IsTimerActive(StunTimer))
		GetWorldTimerManager().ClearTimer(StunTimer);
	
	GetWorldTimerManager().SetTimer(StunTimer, this, &APlayerZDCharacter::OnStunTimerTimeout, 1.0f, false, DurationInSeconds);
	GetAnimInstance()->StopAllAnimationOverrides();
	EnableAttackCollisionBox(false);
}

void APlayerZDCharacter::OnStunTimerTimeout()
{
	IsStunned = false;
}

void APlayerZDCharacter::CollectItem(ECollectableType ItemType)
{
	UGameplayStatics::PlaySound2D(GetWorld(), ItemPickupSound);
	switch (ItemType) {
	case ECollectableType::HealthPotion:
		{
			int HealAmount = 25;
			UpdateHP(HitPoints + HealAmount);
		}break;
	case ECollectableType::Diamond:
		{
			MyGameInstance->AddDiamond(1);
			PlayerHUDWidget->SetDiamonds(MyGameInstance->DiamondCount);
		}break;
	case ECollectableType::DoubleJumpUpgrade:
		{
			if (!MyGameInstance->IsDoubleJumpUnlock)
			{
				MyGameInstance->IsDoubleJumpUnlock = true;
				UnlockDoubleJump();
			}
		}break;
	default :
		{
			
		}break;
	}
	
}

void APlayerZDCharacter::UnlockDoubleJump()
{
	JumpMaxCount = 2;
}

void APlayerZDCharacter::OnRestartTimerTimeout()
{
	MyGameInstance->RestartGame();
}

void APlayerZDCharacter::Deactivate()
{
	if (IsActive)
	{
		IsActive = false;
		CanMove = false;
		CanAttack = false;

		GetCharacterMovement()->StopMovementImmediately();
	}
}

void APlayerZDCharacter::QuitGame()
{
	UKismetSystemLibrary::QuitGame(GetWorld(), UGameplayStatics::GetPlayerController(GetWorld(),0), EQuitPreference::Quit, false);
}


